﻿using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Threading;

namespace RoMBot.Classes
{
    internal static class User32
    {
        // Methods
        [DllImport( "user32.dll" )]
        public static extern IntPtr GetWindowRect( IntPtr hWnd, out RECT lpRect );
        [DllImport( "user32.dll" )]
        public static extern bool PrintWindow( IntPtr hWnd, IntPtr hdcBlt, int nFlags );

        [DllImport( "user32.dll", CharSet = CharSet.Auto )]
        public static extern int GetKeyboardState( byte[] lpKeyState );

        [DllImport( "user32.dll", CharSet = CharSet.Auto )]
        public static extern uint MapVirtualKey( uint uCode, uint uMapType );

        [DllImport( "user32.dll", CharSet = CharSet.Auto )]
        public static extern bool PostMessage( int hhwnd, uint msg, UIntPtr wparam, UIntPtr lparam );

        [DllImport( "user32.dll", CharSet = CharSet.Auto )]
        public static extern bool SetKeyboardState( byte[] lpKeyState );

        [DllImport( "user32.dll", CharSet = CharSet.Auto )]
        public static extern short GetAsyncKeyState( int key );

        [DllImport( "user32.dll" )]
        private static extern int SetForegroundWindow( IntPtr hWnd );

        private const int SW_RESTORE = 9;

        [DllImport( "user32.dll" )]
        private static extern IntPtr ShowWindow( IntPtr hWnd, int nCmdShow );

        [DllImport( "user32.dll" )]
        public static extern IntPtr GetForegroundWindow();

        public static Bitmap PrintWindow( IntPtr hwnd )
        {
            // You need to focus on the application
            SetForegroundWindow( hwnd );
            ShowWindow( hwnd, SW_RESTORE );

            // You need some amount of delay, but 1 second may be overkill
            Thread.Sleep( 1000 );

            RECT rect;
            var error = GetWindowRect( hwnd, out rect );

            // sometimes it gives error.
            while ( error == ( IntPtr ) 0 )
            {
                error = GetWindowRect( hwnd, out rect );
            }

            var width = rect.Right - rect.Left;
            var height = rect.Bottom - rect.Top;

            var bmp = new Bitmap( width, height, PixelFormat.Format32bppArgb );
            Graphics.FromImage( bmp ).CopyFromScreen( rect.Left,
                                                   rect.Top,
                                                   0,
                                                   0,
                                                   new Size( width, height ),
                                                   CopyPixelOperation.SourceCopy );

            return bmp;
        }
    }

    [StructLayout( LayoutKind.Sequential )]
    public struct RECT
    {
        private int _Left;
        private int _Top;
        private int _Right;
        private int _Bottom;

        public RECT( RECT rectangle )
            : this( rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom )
        {
        }
        public RECT( int left, int top, int right, int bottom )
        {
            _Left = left;
            _Top = top;
            _Right = right;
            _Bottom = bottom;
        }

        public int X
        {
            get { return _Left; }
            set { _Left = value; }
        }
        public int Y
        {
            get { return _Top; }
            set { _Top = value; }
        }
        public int Left
        {
            get { return _Left; }
            set { _Left = value; }
        }
        public int Top
        {
            get { return _Top; }
            set { _Top = value; }
        }
        public int Right
        {
            get { return _Right; }
            set { _Right = value; }
        }
        public int Bottom
        {
            get { return _Bottom; }
            set { _Bottom = value; }
        }
        public int Height
        {
            get { return _Bottom - _Top; }
            set { _Bottom = value + _Top; }
        }
        public int Width
        {
            get { return _Right - _Left; }
            set { _Right = value + _Left; }
        }
        public Point Location
        {
            get { return new Point( Left, Top ); }
            set
            {
                _Left = value.X;
                _Top = value.Y;
            }
        }
        public Size Size
        {
            get { return new Size( Width, Height ); }
            set
            {
                _Right = value.Width + _Left;
                _Bottom = value.Height + _Top;
            }
        }

        public static implicit operator Rectangle( RECT rectangle )
        {
            return new Rectangle( rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height );
        }
        public static implicit operator RECT( Rectangle rectangle )
        {
            return new RECT( rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom );
        }
        public static bool operator ==( RECT rectangle1, RECT rectangle2 )
        {
            return rectangle1.Equals( rectangle2 );
        }
        public static bool operator !=( RECT rectangle1, RECT rectangle2 )
        {
            return !rectangle1.Equals( rectangle2 );
        }

        public override string ToString()
        {
            return "{Left: " + _Left + "; " + "Top: " + _Top + "; Right: " + _Right + "; Bottom: " + _Bottom + "}";
        }

        public override int GetHashCode()
        {
            return ToString().GetHashCode();
        }

        public bool Equals( RECT rectangle )
        {
            return rectangle.Left == _Left && rectangle.Top == _Top && rectangle.Right == _Right && rectangle.Bottom == _Bottom;
        }

        public override bool Equals( object Object )
        {
            if ( Object is RECT )
            {
                return Equals( ( RECT ) Object );
            }
            if ( Object is Rectangle )
            {
                return this.Equals( new RECT( ( Rectangle ) Object ) );
            }

            return false;
        }
    }
}
